package cadtoolbox.utils;
import java.awt.geom.Point2D;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;

import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.MutableTreeNode;
import javax.xml.transform.Templates;

import cadtoolbox.optimizer.Parameter;

import cadtoolbox.model.AbstractInput;
import cadtoolbox.model.Constants;
import cadtoolbox.model.ExternalInput;
import cadtoolbox.model.OligoGraph;
import cadtoolbox.model.OligoSystem;
import cadtoolbox.model.PulseInput;
import cadtoolbox.model.SequenceVertex;

import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.visualization.layout.PersistentLayoutImpl.RandomPointFactory;


public class CodeGenerator<E> {

	
	private static <E> String mathematicaParameters(OligoGraph<SequenceVertex,E> graph){
		String ret = "";
		E inhibitedEdge;
		SequenceVertex inhibitedFrom,inhibitedTo;
		for (SequenceVertex seq: graph.getVertices()){
			if (graph.isInhibitor(seq)){
				inhibitedEdge = graph.getInhibitedEdge(seq);
				inhibitedFrom = graph.getEndpoints(inhibitedEdge).getFirst();
				inhibitedTo = graph.getEndpoints(inhibitedEdge).getSecond();
				ret += "Subscript[Kinhib, Subscript[in, "+inhibitedFrom.ID+" -> "+inhibitedTo.ID+"]] ="+graph.getK(seq)*Constants.alpha*Constants.Kduplex+";\n";
				ret += "Subscript[K, Subscript[in, "+inhibitedFrom.ID+" -> "+inhibitedTo.ID+"]] ="+graph.getK(seq)*Constants.Kduplex+";\n";
				ret += "Subscript[d, Subscript[in, "+inhibitedFrom.ID+" -> "+inhibitedTo.ID+"]] = 190/135;\n";
			}else {
			ret += "Subscript[K, Subscript[s, "+(seq.ID)+"]] = "+graph.getK(seq)*Constants.Kduplex+";\n";
			ret += "Subscript[d, Subscript[s, "+(seq.ID)+"]] = 190/300;\n";
			}
		}
		ret+="\n";
		return ret;
	}

	private static <E> String mathematicaSetInit(OligoGraph<SequenceVertex,E> graph){
		String ret="seqinits = { ";
		E inhibitedEdge;
		for (SequenceVertex seq: realSeqs(graph)){
			if (!graph.isInhibitor(seq)){
				ret+="Subscript[s, "+(seq.ID)+"][0] == "+seq.initialConcentration+","; 
			} else {
				inhibitedEdge = graph.getInhibitedEdge(seq);
				ret+="Subscript[in, "+(graph.getSource(inhibitedEdge).ID)+" -> "+(graph.getDest(inhibitedEdge).ID)+"][0] == "+seq.initialConcentration+",";
			}
		}
		ret = ret.substring(0,ret.length()-1); //removal of the last ","
		ret +="};\n";
		return ret;
	}

	private static <E> ArrayList<SequenceVertex> realSeqs(OligoGraph<SequenceVertex,E> graph){
		ArrayList<SequenceVertex> real = new ArrayList<SequenceVertex>();
		SequenceVertex from, to;
		for (E temp : graph.getEdges()){
			from = graph.getSource(temp);
			to = graph.getDest(temp);
			if (!real.contains(from)){
				real.add(from);
			}
			if (!real.contains(to)){
				real.add(to);
			}
		}
		return real;
	}

	private static <E> String mathematicaInputs(OligoGraph<SequenceVertex,E> graph){
		String ret = "Ext = {";
		boolean correct = false;
		for (SequenceVertex seq: graph.getVertices()){
			for (AbstractInput in : seq.inputs){
			ret += in.toMathematica(seq)+",";
			correct = true;
			}	
		}
		if (correct){
			ret = ret.substring(0,ret.length()-1);

		}
		ret+="};\n";
		return ret;
		}
	
	public static <E> String exportToMathematicaCode(OligoGraph<SequenceVertex,E> graph){
		SequenceVertex from, to;
		E inhibitedEdge;
		String res = "T=SparseArray[{";
		for( E temp: graph.getEdges()){
			res+="{";
			from = graph.getSource(temp);
			to = graph.getDest(temp);
			if(graph.isInhibitor(to)){
				inhibitedEdge = graph.getInhibitedEdge(to);
				res+=""+(from.ID+1)+","+(graph.getSource(inhibitedEdge).ID)+","+(graph.getDest(inhibitedEdge).ID)+"}->"+graph.getTemplateConcentration(temp)+",";
			} else {
				res+="1,"+(from.ID)+","+(to.ID)+"}->"+graph.getTemplateConcentration(temp)+",";
			}
		}
		res = res.substring(0,res.length()-1); //removal of the last ","
		res +="}];\n";
		InputStream in = (graph.saturablePoly?CodeGenerator.class.getResourceAsStream("templatepoly"):CodeGenerator.class.getResourceAsStream("template"));
		StringBuffer fileData = new StringBuffer();
		try {
			BufferedReader reader = new BufferedReader(
					new InputStreamReader(in));
			String line = null;
			while ((line = reader.readLine()) != null) {
				fileData.append(line+"\n");
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		String var="";
		if (graph.getVertexCount() > 1){
			var +="{";
		}
		for (SequenceVertex seq : graph.getVertices()){
			var+="Subscript["+(graph.isInhibitor(seq)?"in,"+graph.getSource(graph.getInhibitedEdge(seq)).ID+"->"+graph.getDest(graph.getInhibitedEdge(seq)).ID+"]":"s,"+seq.ID+"]")+"[t],";
		}
		if (graph.getVertexCount() >0){
			var = var.substring(0,var.length()-1);
		}
		if (graph.getVertexCount() >1){
			var += "}";
		}
		return fileData.toString().replace("<seqinits>",mathematicaSetInit(graph)).replace("<params>", mathematicaParameters(graph)).replace("<vars>",var).replace("<temps>",res).replace("<exts>", mathematicaInputs(graph));
	}
	
	public static <E> String saveGraph(OligoGraph<SequenceVertex, E> graph, Layout<SequenceVertex, E> layout){
		String res = "SEQ\n";
		for (SequenceVertex v: graph.getVertices()){
			res += v.ID+"\t"+v.initialConcentration+"\t"+layout.transform(v).getX()+"\t"+layout.transform(v).getY()+"\t"+graph.getK(v)+"\n";
		}
		res+= "TEM\n";
		for (E e: graph.getEdges()){
			res += e.toString() +"\t"+graph.getSource(e).ID+"\t"+graph.getDest(e).ID+"\t"+graph.getTemplateConcentration(e)+"\n";
		}
		res+= "INHIB\n";
		for (SequenceVertex v: graph.inhibitors.keySet()){
			res += v.ID+"\t"+graph.getInhibitedEdge(v).toString() +"\t"+graph.getSource(graph.getInhibitedEdge(v)).ID+"\t"+graph.getDest(graph.getInhibitedEdge(v)).ID+"\n";
		}
		res+= "INPUTS\n";
		for (SequenceVertex v: graph.getVertices()){
			for(AbstractInput inp: v.inputs){
				if(inp.getClass() == PulseInput.class){
					PulseInput pu = (PulseInput) inp;
					res += v.ID+"\t"+"pulse"+"\t"+(int)pu.pulseTime+"\t"+pu.ampli+"\t"+(pu.periodic?(int)pu.period:"")+"\n";
				} else if(inp.getClass() == ExternalInput.class){
					ExternalInput ext = (ExternalInput) inp;
					res += v.ID+"\t"+"file"+"\t"+ext.file+"\n";
				}
			}
		}
		res+= "PARAMS\n";
		res+= "absprec\t"+Constants.absprec;
		res+= "\nrelprec\t"+Constants.relprec;
		res+= "\ninhfact\t"+Constants.alpha;
		res+= "\ndiplrat\t"+Constants.displ;
		res+= "\nexokmib\t"+Constants.exoKmInhib;
		res+= "\nexokmsi\t"+Constants.exoKmSimple;
		res+= "\nexokmtm\t"+Constants.exoKmTemplate;
		res+= "\nexovm\t"+Constants.exoVm;
		res+= "\nkduplex\t"+Constants.Kduplex;
		res+= "\nnickkm\t"+Constants.nickKm;
		res+= "\nnickvm\t"+Constants.nickVm;
		res+= "\nmaxtime\t"+Constants.numberOfPoints;
		res+= "\npolkm\t"+Constants.polKm;
		res+= "\npolkmbo\t"+Constants.polKmBoth;
		res+= "\npolvm\t"+Constants.polVm;
		res+= "\nselfsta\t"+Constants.ratioSelfStart;
		res+= "\ntoehold\t"+Constants.ratioToehold;
		if(!graph.getNotPlottedSeqs().isEmpty()){
			res+="\nnotplot\t";
			for(SequenceVertex n : graph.getNotPlottedSeqs()){
				res+=""+n.ID+" ";
			}
		}
		
		return res;
	}
	
	public static <E> void openGraph(OligoGraph<SequenceVertex,E> graph, Layout<SequenceVertex,E> layout, File file){
		SequenceVertex newv;
		E newEdge;
		try {
			FileReader in = new FileReader(file);
			BufferedReader reader = new BufferedReader(in);
			String line = null;
			line = reader.readLine();
			String[] split;
			if (line.startsWith("SEQ")){

				//TODO: I should parse the file first... BUT I AM LAZYYYYY. Also, available seqs?
				graph.totalReset();
				
				HashMap<Integer,SequenceVertex> idvertices = new HashMap<Integer,SequenceVertex>();
				boolean changeKInhib = false;
				while (!(line = reader.readLine()).startsWith("TEM")) { 
					split= line.split("\t");
					newv = new SequenceVertex(Integer.valueOf(split[0]),Double.valueOf(split[1]));
					idvertices.put(Integer.valueOf(split[0]), newv);
					graph.addVertex(newv);
					if(split.length >= 5){
						graph.K.put(newv, Double.valueOf(split[4]));
					} else {
						graph.K.put(newv, Constants.Kduplex/Constants.PadiracKSimpleDiv);
						changeKInhib = true;
					}
					if(newv != null){
						Parameter tempSeqK = null;
						//seqK
						Enumeration<DefaultMutableTreeNode> it = ((MutableTreeNode) graph.optimizable.getChild(graph.optimizable.getRoot(), 0)).children();
						while(it.hasMoreElements()){
							DefaultMutableTreeNode next = it.nextElement();
							if(((Parameter) next.getUserObject()).target.equals(newv)){
								tempSeqK = (Parameter) next.getUserObject();
								break;
							}
						}
						if(tempSeqK != null){
							tempSeqK.currentValue = graph.getK(newv);
							tempSeqK.minValue = graph.isInhibitor(newv)? Constants.inhibKmin : Constants.simpleKmin;
							tempSeqK.maxValue = graph.isInhibitor(newv)? Constants.inhibKmax : Constants.simpleKmax;
						}
						//seqC
						it = ((MutableTreeNode) graph.optimizable.getChild(graph.optimizable.getRoot(), 1)).children();
						while(it.hasMoreElements()){
							DefaultMutableTreeNode next = it.nextElement();
							if(((Parameter) next.getUserObject()).target.equals(newv)){
								tempSeqK = (Parameter) next.getUserObject();
								break;
							}
						}
						if(tempSeqK != null){
							tempSeqK.currentValue = ((SequenceVertex) newv).initialConcentration;
							tempSeqK.minValue = 0;
							tempSeqK.maxValue = 100;
						}
					}
					layout.setLocation(newv, new Point2D.Double(Double.valueOf(split[2]), Double.valueOf(split[3])));
				}
				while (!(line = reader.readLine()).startsWith("INHIB")) {
					split= line.split("\t");
					newEdge = graph.getEdgeFactory().createEdge(idvertices.get(Integer.valueOf(split[1])), idvertices.get(Integer.valueOf(split[2])));
					graph.addActivation(newEdge, idvertices.get(Integer.valueOf(split[1])), idvertices.get(Integer.valueOf(split[2])), Double.valueOf(split[3]));
				}
				while ((line = reader.readLine()) != null && !line.startsWith("INPUTS") && !line.startsWith("PARAMS")){
					split= line.split("\t");
					newEdge = graph.findEdge(idvertices.get(Integer.valueOf(split[2])), idvertices.get(Integer.valueOf(split[3])));
					graph.addInhibition(newEdge, idvertices.get(Integer.valueOf(split[0])));
					idvertices.get(Integer.valueOf(split[0])).setInhib(true);
					if(changeKInhib){
						graph.K.put(idvertices.get(Integer.valueOf(split[0])), Constants.Kduplex/Constants.PadiracKInhibDiv);
					}
				}
				while((line = reader.readLine()) != null && !line.startsWith("PARAMS")){
					split= line.split("\t");
					SequenceVertex v = idvertices.get(Integer.valueOf(split[0]));
					if(split[1].equals("pulse")){
						PulseInput newinp = new PulseInput(Integer.valueOf(split[2]),Double.valueOf(split[3]));
						if(split.length>4){
							newinp.periodic = true;
							newinp.period = Integer.valueOf(split[4]);
						}
						v.inputs.add(newinp);
					} else if(split[1].equals("file")){
						File open = new File(split[2]);
						try {
							FileReader inin = new FileReader(open);
							BufferedReader readerin = new BufferedReader(inin);
							String linein = null;
							linein = readerin.readLine();
							String[] splitin;
							ArrayList<Double> values = new ArrayList<Double>();
							while ((linein = readerin.readLine()) != null){
								splitin= linein.split("\t");
								for(int i=0; i<splitin.length;i++){
									values.add(Double.parseDouble(splitin[i]));
								}
							}
							Double[] inp = new Double[values.size()];
							inp = values.toArray(inp);
							v.inputs.add(new ExternalInput(inp,open));
						} catch (Exception e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				}
				//PARAMS
				while ((line = reader.readLine()) != null){
					split = line.split("\t");
					//Could use a switch if we were using Java 7. Better to stay compatible with 5
					
					if(split[0].equals("absprec")){
						Constants.absprec = Double.parseDouble(split[1]);
					} else if(split[0].equals("relprec")){
						Constants.relprec = Double.parseDouble(split[1]);
					} else if(split[0].equals("inhfact")){
						Constants.alpha = Double.parseDouble(split[1]);
					} else if(split[0].equals("diplrat")){
						Constants.displ = Double.parseDouble(split[1]);
					} else if(split[0].equals("exokmib")){
						Constants.exoKmInhib = Double.parseDouble(split[1]);
					} else if(split[0].equals("exokmsi")){
						Constants.exoKmSimple = Double.parseDouble(split[1]);
					} else if(split[0].equals("exokmtm")){
						Constants.exoKmTemplate = Double.parseDouble(split[1]);
					} else if(split[0].equals("exovm")){
						Constants.exoVm = Double.parseDouble(split[1]);
					} else if(split[0].equals("kduplex")){
						Constants.Kduplex = Double.parseDouble(split[1]);
					} else if(split[0].equals("nickkm")){
						Constants.nickKm = Double.parseDouble(split[1]);
					} else if(split[0].equals("nickvm")){
						Constants.nickVm = Double.parseDouble(split[1]);
					} else if(split[0].equals("maxtime")){
						Constants.numberOfPoints = Integer.parseInt(split[1]);
					} else if(split[0].equals("polkm")){
						Constants.polKm = Double.parseDouble(split[1]);
					} else if(split[0].equals("polkmbo")){
						Constants.polKmBoth = Double.parseDouble(split[1]);
					} else if(split[0].equals("polvm")){
						Constants.polVm = Double.parseDouble(split[1]);
					} else if(split[0].equals("selfsta")){
						Constants.ratioSelfStart = Double.parseDouble(split[1]);
					} else if(split[0].equals("toehold")){
						Constants.ratioToehold = Double.parseDouble(split[1]);
					} else if(split[0].equals("notplot")){
						String[] splot = split[1].split(" ");
						for(int i=0; i<splot.length;i++){
							SequenceVertex remseq = graph.getEquivalentVertex(new SequenceVertex(Integer.parseInt(splot[i])));
							graph.removePlottedSeq(remseq);
						}
					}
				}
			}
			graph.saved = true; // we just loaded it...
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	/** importGraph adds the import to the current system instead of overwriting it.
	 * 	PARAMS are ignored
	 * @param <E>
	 * @param graph
	 * @param file
	 */
	public static <E> void importGraph(OligoGraph<SequenceVertex,E> graph, Layout<SequenceVertex,E> layout, File file){
		SequenceVertex newv;
		E newEdge;
		try {
			FileReader in = new FileReader(file);
			BufferedReader reader = new BufferedReader(in);
			String line = null;
			line = reader.readLine();
			String[] split;
			boolean changeKInhib = false;
			if (line.startsWith("SEQ")){

				
				//graph.reset();
				HashMap<Integer,SequenceVertex> idvertices = new HashMap<Integer,SequenceVertex>();
				while (!(line = reader.readLine()).startsWith("TEM")) { 
					split= line.split("\t");
					newv = graph.getVertexFactory().create();
					newv.setInitialConcentration(Double.valueOf(split[1]));
					idvertices.put(Integer.valueOf(split[0]), newv);
					graph.addVertex(newv);
					if(split.length >= 5){
						graph.K.put(newv, Double.valueOf(split[4]));
					} else {
						graph.K.put(newv, Constants.Kduplex/Constants.PadiracKSimpleDiv);
						changeKInhib = true;
					}
					if(newv != null){
						Parameter tempSeqK = null;
						//seqK
						Enumeration<DefaultMutableTreeNode> it = ((MutableTreeNode) graph.optimizable.getChild(graph.optimizable.getRoot(), 0)).children();
						while(it.hasMoreElements()){
							DefaultMutableTreeNode next = it.nextElement();
							if(((Parameter) next.getUserObject()).target.equals(newv)){
								tempSeqK = (Parameter) next.getUserObject();
								break;
							}
						}
						if(tempSeqK != null){
							tempSeqK.currentValue = graph.getK(newv);
							tempSeqK.minValue = graph.isInhibitor(newv)? Constants.inhibKmin : Constants.simpleKmin;
							tempSeqK.maxValue = graph.isInhibitor(newv)? Constants.inhibKmax : Constants.simpleKmax;
						}
						//seqC
						it = ((MutableTreeNode) graph.optimizable.getChild(graph.optimizable.getRoot(), 1)).children();
						while(it.hasMoreElements()){
							DefaultMutableTreeNode next = it.nextElement();
							if(((Parameter) next.getUserObject()).target.equals(newv)){
								tempSeqK = (Parameter) next.getUserObject();
								break;
							}
						}
						if(tempSeqK != null){
							tempSeqK.currentValue = ((SequenceVertex) newv).initialConcentration;
							tempSeqK.minValue = 0;
							tempSeqK.maxValue = 100;
						}
					}
					layout.setLocation(newv, new Point2D.Double(Double.valueOf(split[2]), Double.valueOf(split[3])));
				}
				while (!(line = reader.readLine()).startsWith("INHIB")) {
					split= line.split("\t");
					newEdge = graph.getEdgeFactory().createEdge(idvertices.get(Integer.valueOf(split[1])), idvertices.get(Integer.valueOf(split[2])));
					graph.addActivation(newEdge, idvertices.get(Integer.valueOf(split[1])), idvertices.get(Integer.valueOf(split[2])), Double.valueOf(split[3]));
				}
				
				while ((line = reader.readLine()) != null && !line.startsWith("INPUTS") && !line.startsWith("PARAMS")){
					split= line.split("\t");
					newEdge = graph.findEdge(idvertices.get(Integer.valueOf(split[2])), idvertices.get(Integer.valueOf(split[3])));
					graph.addInhibition(newEdge, idvertices.get(Integer.valueOf(split[0])));
					idvertices.get(Integer.valueOf(split[0])).setInhib(true);
					if(changeKInhib){
						graph.K.put(idvertices.get(Integer.valueOf(split[0])), Constants.Kduplex/Constants.PadiracKInhibDiv);
					}
				} 
				while((line = reader.readLine()) != null && !line.startsWith("PARAMS")){
					split= line.split("\t");
					SequenceVertex v = idvertices.get(Integer.valueOf(split[0]));
					if(split[1].equals("pulse")){
						PulseInput newinp = new PulseInput(Integer.valueOf(split[2]),Double.valueOf(split[3]));
						if(split.length>4){
							newinp.periodic = true;
							newinp.period = Integer.valueOf(split[4]);
						}
						v.inputs.add(newinp);
					} else if(split[1].equals("file")){
						File open = new File(split[2]);
						try {
							FileReader inin = new FileReader(open);
							BufferedReader readerin = new BufferedReader(inin);
							String linein = null;
							linein = readerin.readLine();
							String[] splitin;
							ArrayList<Double> values = new ArrayList<Double>();
							while ((linein = readerin.readLine()) != null){
								splitin= linein.split("\t");
								for(int i=0; i<splitin.length;i++){
									values.add(Double.parseDouble(splitin[i]));
								}
							}
							Double[] inp = new Double[values.size()];
							inp = values.toArray(inp);
							v.inputs.add(new ExternalInput(inp,open));
						} catch (Exception e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				}
			}
			graph.replot();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static <E> String SBMLspecies(OligoGraph<SequenceVertex,E> graph){
		String result = "";
		for(SequenceVertex seq: graph.getVertices()){
			result+="<species id=\"s"+seq.ID+"\" compartment=\"TestTube\" initialConcentration=\""+seq.initialConcentration+"\" hasOnlySubstanceUnits=\"false\" boundaryCondition=\"false\" constant=\"false\"/>\n";
		}
		SequenceVertex from,to;
		for(E temp: graph.getEdges()){
			from = graph.getEndpoints(temp).getFirst();
			to = graph.getEndpoints(temp).getSecond();
			result+="<species id=\"talone"+from.ID+"to"+to.ID+"\" compartment=\"TestTube\" initialConcentration=\""+graph.getTemplateConcentration(temp)+"\" hasOnlySubstanceUnits=\"false\" boundaryCondition=\"false\" constant=\"false\"/>\n";
			result+="<species id=\"tin"+from.ID+"to"+to.ID+"\" compartment=\"TestTube\" initialConcentration=\"0\" hasOnlySubstanceUnits=\"false\" boundaryCondition=\"false\" constant=\"false\"/>\n";
			result+="<species id=\"tout"+from.ID+"to"+to.ID+"\" compartment=\"TestTube\" initialConcentration=\"0\" hasOnlySubstanceUnits=\"false\" boundaryCondition=\"false\" constant=\"false\"/>\n";
			result+="<species id=\"tboth"+from.ID+"to"+to.ID+"\" compartment=\"TestTube\" initialConcentration=\"0\" hasOnlySubstanceUnits=\"false\" boundaryCondition=\"false\" constant=\"false\"/>\n";
			result+="<species id=\"text"+from.ID+"to"+to.ID+"\" compartment=\"TestTube\" initialConcentration=\"0\" hasOnlySubstanceUnits=\"false\" boundaryCondition=\"false\" constant=\"false\"/>\n";
			if (graph.inhibitors.containsValue(temp)){
				result+="<species id=\"tinhib"+from.ID+"to"+to.ID+"\" compartment=\"TestTube\" initialConcentration=\"0\" hasOnlySubstanceUnits=\"false\" boundaryCondition=\"false\" constant=\"false\"/>\n";

			}
		}
		return result;
	}
	
	public static <E> String SBMLparams(OligoGraph<SequenceVertex,E> graph){
		String result = "";
		result+= "<parameter id=\"kduplex\" value=\""+Constants.Kduplex+"\" units=\"litre_per_nanoMole_per_minute\" constant=\"true\"/>\n";
		result+= "<parameter id=\"displ\" value=\""+Constants.displ+"\" units=\"dimensionless\" constant=\"true\"/>\n";
		if(graph.saturableExo){
			double value = 0;
			for (SequenceVertex s: graph.getVertices()) {
				value += s.initialConcentration
						/ (graph.inhibitors.containsKey(s)?Constants.exoKmInhib:Constants.exoKmSimple);
			}
			if(graph.exoSaturationByFreeTemplates){
				for(E temp: graph.getEdges()){
					value += graph.getTemplateConcentration(temp)/Constants.exoKmTemplate;
				}
			}
			double observedExoKm = 1 + value;
			result+= "<parameter id=\"exosimple\" value=\""+Constants.exoVm/(Constants.exoKmSimple*observedExoKm)+"\" units=\"per_minute\" constant=\"false\"/>\n";
			result+= "<parameter id=\"exoinhib\" value=\""+Constants.exoVm/(Constants.exoKmInhib*observedExoKm)+"\" units=\"per_minute\" constant=\"false\"/>\n";
		} else {
			result+= "<parameter id=\"exosimple\" value=\""+Constants.exoVm/Constants.exoKmSimple+"\" units=\"per_minute\" constant=\"true\"/>\n";
			result+= "<parameter id=\"exoinhib\" value=\""+Constants.exoVm/Constants.exoKmInhib+"\" units=\"per_minute\" constant=\"true\"/>\n";
		}
		if(graph.saturablePoly){
			result+= "<parameter id=\"pol\" value=\""+Constants.polVm/(Constants.polKm)+"\" units=\"per_minute\" constant=\"false\"/>\n";
			result+= "<parameter id=\"polboth\" value=\""+Constants.polVm/(Constants.polKmBoth)+"\" units=\"per_minute\" constant=\"false\"/>\n";
		} else {
			result+= "<parameter id=\"pol\" value=\""+Constants.polVm/(Constants.polKm)+"\" units=\"per_minute\" constant=\"true\"/>\n";
			result+= "<parameter id=\"polboth\" value=\""+Constants.polVm/(Constants.polKmBoth)+"\" units=\"per_minute\" constant=\"true\"/>\n";
		}
		if(graph.saturableNick){
			result+= "<parameter id=\"nick\" value=\""+Constants.nickVm/(Constants.nickKm)+"\" units=\"per_minute\" constant=\"false\"/>\n";
		} else {
			result+= "<parameter id=\"nick\" value=\""+Constants.nickVm/(Constants.nickKm)+"\" units=\"per_minute\" constant=\"true\"/>\n";
		}
		if(graph.selfStart){
			result+= "<parameter id=\"polZerothOrderLeak\" value=\""+Constants.ratioSelfStart+"\" units=\"dimensionless\" constant=\"false\"/>\n";
		}
		if(Constants.ratioToehold > 0){
			result+= "<parameter id=\"tau\" value=\""+Constants.ratioToehold+"\" units=\"dimensionless\" constant=\"true\"/>\n";
		}
		result+= "<parameter id=\"alpha\" value=\""+Constants.alpha+"\" units=\"dimensionless\" constant=\"true\"/>\n";
		for(SequenceVertex seq : graph.getVertices()){
			if (!graph.isInhibitor(seq)){
				result+= "<parameter id=\"ks"+seq.ID+"\" value=\""+1/Constants.PadiracKSimpleDiv+"\" units=\"litre_per_nanoMole\" constant=\"true\"/>\n";
			} else {
				result+= "<parameter id=\"ks"+seq.ID+"\" value=\""+1/Constants.PadiracKInhibDiv+"\" units=\"litre_per_nanoMole\" constant=\"true\"/>\n";
			}
		}
		return result;
	}
	
	public static <E> String SBMLrules(OligoGraph<SequenceVertex,E> graph){
		//parameters update with saturation
		String result = "";
		if(graph.coupling&&(graph.saturableExo || graph.saturableNick || graph.saturablePoly)){
			result+="<listOfRules>\n";
			if(graph.saturableExo){
				
			result+="<assignmentRule variable=\"exosimple\">\n"
			+ "<math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n"
			+ "<apply> <divide/> <cn> "+Constants.exoVm+"</cn>\n" 
				+ "<apply> <times/> <cn> "+Constants.exoKmSimple+"</cn>\n"
					+ "<apply> <plus/>\n"
						+ "<cn> 1 </cn>\n";
						for (SequenceVertex s: graph.getVertices()) {
							result+="<apply> <divide/> <ci> s"+s.ID+" </ci> <cn> "+(graph.isInhibitor(s)?Constants.exoKmInhib:Constants.exoKmSimple)+" </cn> </apply>\n";
						}
						if(graph.exoSaturationByFreeTemplates){
							for(E temp: graph.getEdges()){
								result += "<apply> <divide/> <ci> text"+graph.getEndpoints(temp).getFirst().ID+"to"+graph.getEndpoints(temp).getSecond().ID+" </ci> <cn> "+Constants.exoKmTemplate+" </cn> </apply>\n";
							}
						}
			result+="</apply>\n</apply>\n</apply>\n"
			+ "</math>\n"
			+ "</assignmentRule>\n";
			result+="<assignmentRule variable=\"exoinhib\">\n"
				+ "<math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n"
				+ "<apply> <divide/> <cn> "+Constants.exoVm+"</cn>\n" 
					+ "<apply> <times/> <cn> "+Constants.exoKmInhib+"</cn>\n"
						+ "<apply> <plus/>\n"
							+ "<cn> 1 </cn>\n";
							for (SequenceVertex s: graph.getVertices()) {
								result+="<apply> <divide/> <ci> s"+s.ID+" </ci> <cn> "+(graph.isInhibitor(s)?Constants.exoKmInhib:Constants.exoKmSimple)+" </cn> </apply>\n";
							}
							if(graph.exoSaturationByFreeTemplates){
								for(E temp: graph.getEdges()){
									result += "<apply> <divide/> <ci> text"+graph.getEndpoints(temp).getFirst().ID+"to"+graph.getEndpoints(temp).getSecond().ID+" </ci> <cn> "+Constants.exoKmTemplate+" </cn> </apply>\n";
								}
							}
				result+="</apply>\n</apply>\n</apply>\n"
				+ "</math>\n"
				+ "</assignmentRule>\n";
			}
			if(graph.saturableNick){
				result+="<assignmentRule variable=\"nick\">\n"
					+ "<math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n"
					+ "<apply> <divide/> <cn> "+Constants.nickVm+"</cn>\n" 
						+ "<apply> <times/> <cn> "+Constants.nickKm+"</cn>\n"
							+ "<apply> <plus/>\n"
								+ "<cn> 1 </cn>\n";
								for (E temp: graph.getEdges()) {
									result+="<apply> <divide/> <ci> text"+graph.getEndpoints(temp).getFirst().ID+"to"+graph.getEndpoints(temp).getSecond().ID+" </ci> <cn> "+Constants.nickKm+" </cn> </apply>\n";
								}
					result+="</apply>\n</apply>\n</apply>\n"
					+ "</math>\n"
					+ "</assignmentRule>\n";
			}
			if(graph.saturablePoly){
				result+="<assignmentRule variable=\"pol\">\n"
					+ "<math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n"
					+ "<apply> <divide/> <cn> "+Constants.polVm+"</cn>\n" 
						+ "<apply> <times/> <cn> "+Constants.polKm+"</cn>\n"
							+ "<apply> <plus/>\n"
								+ "<cn> 1 </cn>\n";
								for (E temp: graph.getEdges()) {
									result+="<apply> <divide/> <ci> tin"+graph.getEndpoints(temp).getFirst().ID+"to"+graph.getEndpoints(temp).getSecond().ID+" </ci> <cn> "+Constants.polKm+" </cn> </apply>\n";
									result+="<apply> <divide/> <ci> tboth"+graph.getEndpoints(temp).getFirst().ID+"to"+graph.getEndpoints(temp).getSecond().ID+" </ci> <cn> "+Constants.polKm+" </cn> </apply>\n";
								}
					result+="</apply>\n</apply>\n</apply>\n"
					+ "</math>\n"
					+ "</assignmentRule>\n";
			}
			result+= "</listOfRules>\n";
		}
		return result;
	}
	
	public static <E> String SBMLreactions(OligoGraph<SequenceVertex,E> graph){
		String result = "";
		int reactionnumber = 0;
		int inputnumber = 0;
		//Exonuclease
		for(SequenceVertex seq: graph.getVertices()){
			result+="<reaction id=\"R"+reactionnumber+"\" reversible=\"false\" fast=\"false\">\n"
			  +"<listOfReactants>\n"
			  +"<speciesReference species=\"s"+seq.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"</listOfReactants>\n"
			  +"<kineticLaw>\n"
			  +"<math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n";
			  if(graph.coupling||!graph.saturableExo){
			  result+="<apply>\n"
			  +"<times/> <ci> "+(graph.isInhibitor(seq)?"exoinhib":"exosimple")+" </ci> <ci> s"+seq.ID+" </ci>\n"
			  +"</apply>\n";
			  } else {
			  result+= "<apply>\n"
				+"<times/> \n"
				+"<apply> <divide/> <cn> "+Constants.exoVm+"</cn>\n" 
				+ "<apply> <times/> <cn> "+(graph.isInhibitor(seq)?Constants.exoKmInhib:Constants.exoKmSimple)+"</cn>\n"
				+ "<apply> <plus/>\n"
				+ "<cn> 1 </cn>\n"
				+"<apply> <divide/> <ci> s"+seq.ID+" </ci> <cn> "+(graph.isInhibitor(seq)?Constants.exoKmInhib:Constants.exoKmSimple)+" </cn> </apply>\n";
							
		result+="</apply>\n</apply>\n</apply>\n <ci> s"+seq.ID+" </ci>\n</apply>\n";
			  }
			  result+="</math>\n"
			  + "</kineticLaw>\n"
			  + "</reaction>\n";
			reactionnumber++;
			//Adding pulse inputs
//			for(AbstractInput inp : seq.inputs){
//				result+="<reaction id=\"Input"+inputnumber+"\" reversible=\"false\" fast=\"false\">\n"
//				  +"<listOfProducts>\n"
//				  +"<speciesReference species=\"s"+seq.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
//				  +"</listOfProducts>\n"
//				  +"<kineticLaw>\n"
//				  +"<math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n";
//				result+="</math>\n"
//					  + "</kineticLaw>\n"
//					  + "</reaction>\n";
//			}
		}
		SequenceVertex from, to , inhib;
		for(E temp: graph.getEdges()){
			from = graph.getEndpoints(temp).getFirst();
			to = graph.getEndpoints(temp).getSecond();
			inhib = (graph.getInhibitions().contains(temp)?graph.getInhibition(temp).getLeft():null);
			//talone and input
			result+="<reaction id=\"R"+reactionnumber+"\" reversible=\"true\" fast=\"false\">\n"
			  +"<listOfReactants>\n"
			  +"<speciesReference species=\"s"+from.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"<speciesReference species=\"talone"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"</listOfReactants>\n"
			  +"<listOfProducts>\n"
			  +"<speciesReference species=\"tin"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"</listOfProducts>\n"
			  +"<kineticLaw>\n"
			  +"<math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n"
			  +"<apply>\n"
			  +"<times/> <ci> kduplex </ci> <ci> s"+from.ID+" </ci> <ci> talone"+from.ID+"to"+to.ID+"</ci>\n"
			  +"</apply>\n"
			  +"</math>\n"
			  + "</kineticLaw>\n"
			  + "</reaction>\n";
			reactionnumber++;
			result+="<reaction id=\"R"+reactionnumber+"\" reversible=\"true\" fast=\"false\">\n"
			  +"<listOfReactants>\n"
			  +"<speciesReference species=\"tin"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"</listOfReactants>\n"
			  +"<listOfProducts>\n"
			  +"<speciesReference species=\"s"+from.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"<speciesReference species=\"talone"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"</listOfProducts>\n"
			  +"<kineticLaw>\n"
			  +"<math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n"
			  +"<apply>\n"
			  +"<times/> <ci> kduplex </ci> <ci> ks"+from.ID+" </ci> <ci> tin"+from.ID+"to"+to.ID+"</ci>\n"
			  +"</apply>\n"
			  +"</math>\n"
			  + "</kineticLaw>\n"
			  + "</reaction>\n";
			reactionnumber++;
			// talone and output
			result+="<reaction id=\"R"+reactionnumber+"\" reversible=\"true\" fast=\"false\">\n"
			  +"<listOfReactants>\n"
			  +"<speciesReference species=\"s"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"<speciesReference species=\"talone"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"</listOfReactants>\n"
			  +"<listOfProducts>\n"
			  +"<speciesReference species=\"tout"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"</listOfProducts>\n"
			  +"<kineticLaw>\n"
			  +"<math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n"
			  +"<apply>\n"
			  +"<times/> <ci> kduplex </ci> <ci> s"+to.ID+" </ci> <ci> talone"+from.ID+"to"+to.ID+"</ci>\n"
			  +"</apply>\n"
			  +"</math>\n"
			  + "</kineticLaw>\n"
			  + "</reaction>\n";
			reactionnumber++;
			result+="<reaction id=\"R"+reactionnumber+"\" reversible=\"true\" fast=\"false\">\n"
			  +"<listOfReactants>\n"
			  +"<speciesReference species=\"tout"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"</listOfReactants>\n"
			  +"<listOfProducts>\n"
			  +"<speciesReference species=\"s"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"<speciesReference species=\"talone"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"</listOfProducts>\n"
			  +"<kineticLaw>\n"
			  +"<math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n"
			  +"<apply>\n"
			  +"<times/> <ci> kduplex </ci> <ci> ks"+to.ID+" </ci> <ci> tout"+from.ID+"to"+to.ID+"</ci>\n"
			  +"</apply>\n"
			  +"</math>\n"
			  + "</kineticLaw>\n"
			  + "</reaction>\n";
			reactionnumber++;
			// tin and output
			result+="<reaction id=\"R"+reactionnumber+"\" reversible=\"true\" fast=\"false\">\n"
			  +"<listOfReactants>\n"
			  +"<speciesReference species=\"s"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"<speciesReference species=\"tin"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"</listOfReactants>\n"
			  +"<listOfProducts>\n"
			  +"<speciesReference species=\"tboth"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"</listOfProducts>\n"
			  +"<kineticLaw>\n"
			  +"<math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n"
			  +"<apply>\n"
			  +"<times/> <ci> kduplex </ci> <ci> s"+to.ID+" </ci> <ci> tin"+from.ID+"to"+to.ID+"</ci>\n"
			  +"</apply>\n"
			  +"</math>\n"
			  + "</kineticLaw>\n"
			  + "</reaction>\n";
			reactionnumber++;
			result+="<reaction id=\"R"+reactionnumber+"\" reversible=\"true\" fast=\"false\">\n"
			  +"<listOfReactants>\n"
			  +"<speciesReference species=\"tboth"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"</listOfReactants>\n"
			  +"<listOfProducts>\n"
			  +"<speciesReference species=\"s"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"<speciesReference species=\"tin"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"</listOfProducts>\n"
			  +"<kineticLaw>\n"
			  +"<math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n"
			  +"<apply>\n"
			  +"<times/> <ci> kduplex </ci> <ci> ks"+to.ID+" </ci> <ci> tboth"+from.ID+"to"+to.ID+"</ci>\n"
			  +"</apply>\n"
			  +"</math>\n"
			  + "</kineticLaw>\n"
			  + "</reaction>\n";
			reactionnumber++;
			// tout and input
			result+="<reaction id=\"R"+reactionnumber+"\" reversible=\"true\" fast=\"false\">\n"
			  +"<listOfReactants>\n"
			  +"<speciesReference species=\"s"+from.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"<speciesReference species=\"tout"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"</listOfReactants>\n"
			  +"<listOfProducts>\n"
			  +"<speciesReference species=\"tboth"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"</listOfProducts>\n"
			  +"<kineticLaw>\n"
			  +"<math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n"
			  +"<apply>\n"
			  +"<times/> <ci> kduplex </ci> <ci> s"+from.ID+" </ci> <ci> tout"+from.ID+"to"+to.ID+"</ci>\n"
			  +"</apply>\n"
			  +"</math>\n"
			  + "</kineticLaw>\n"
			  + "</reaction>\n";
			reactionnumber++;
			result+="<reaction id=\"R"+reactionnumber+"\" reversible=\"true\" fast=\"false\">\n"
			  +"<listOfReactants>\n"
			  +"<speciesReference species=\"tboth"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"</listOfReactants>\n"
			  +"<listOfProducts>\n"
			  +"<speciesReference species=\"s"+from.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"<speciesReference species=\"tout"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"</listOfProducts>\n"
			  +"<kineticLaw>\n"
			  +"<math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n"
			  +"<apply>\n"
			  +"<times/> <ci> kduplex </ci> <ci> ks"+from.ID+" </ci> <ci> tboth"+from.ID+"to"+to.ID+"</ci>\n"
			  +"</apply>\n"
			  +"</math>\n"
			  + "</kineticLaw>\n"
			  + "</reaction>\n";
			reactionnumber++;
			// tin and polymerase
			result+="<reaction id=\"R"+reactionnumber+"\" reversible=\"false\" fast=\"false\">\n"
			  +"<listOfReactants>\n"
			  +"<speciesReference species=\"tin"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"</listOfReactants>\n"
			  +"<listOfProducts>\n"
			  +"<speciesReference species=\"text"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"</listOfProducts>\n";
			  if(!graph.coupling&&graph.saturablePoly){
				  result+="<listOfModifiers>\n"
				  +"<modifierSpeciesReference species=\"tboth"+from.ID+"to"+to.ID+"\"/>"
				  +"</listOfModifiers>";

			  }
			  result+="<kineticLaw>\n"
			  +"<math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n"
			  +"<apply>\n"
			  +"<times/> <ci> tin"+from.ID+"to"+to.ID+"</ci>\n";
			  if(graph.coupling||!graph.saturablePoly){
			  result+= "<ci> pol </ci>"
			  ;
			  } else {
			  result+="<apply> <divide/> <cn> "+Constants.polVm+"</cn>\n" 
				+ "<apply> <times/> <cn> "+Constants.polKm+"</cn>\n"
				+ "<apply> <plus/>\n"
				+ "<cn> 1 </cn>\n";
					
						result+="<apply> <divide/> <ci> tin"+from.ID+"to"+to.ID+" </ci> <cn> "+Constants.polKm+" </cn> </apply>\n";
						result+="<apply> <divide/> <ci> tboth"+graph.getEndpoints(temp).getFirst().ID+"to"+graph.getEndpoints(temp).getSecond().ID+" </ci> <cn> "+Constants.polKm+" </cn> </apply>\n";			
		result+="</apply>\n</apply>\n</apply>\n";
			  }
			  result+="</apply>\n"
			  +"</math>\n"
			  + "</kineticLaw>\n"
			  + "</reaction>\n";
			reactionnumber++;
			// tboth and polymerase
			result+="<reaction id=\"R"+reactionnumber+"\" reversible=\"false\" fast=\"false\">\n"
			  +"<listOfReactants>\n"
			  +"<speciesReference species=\"tboth"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"</listOfReactants>\n"
			  +"<listOfProducts>\n"
			  +"<speciesReference species=\"s"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"<speciesReference species=\"text"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"</listOfProducts>\n";
			  if(!graph.coupling&&graph.saturablePoly){
				  result+="<listOfModifiers>\n"
				  +"<modifierSpeciesReference species=\"tin"+from.ID+"to"+to.ID+"\"/>"
				  +"</listOfModifiers>";

			  }
			  result+="<kineticLaw>\n"
			  +"<math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n"
			  +"<apply>\n"
			  +"<times/> <ci> "
			  +" tboth"+from.ID+"to"+to.ID+"</ci>\n";
			  if(graph.coupling||!graph.saturablePoly){
			  result+="<ci>"+ (graph.isInhibitor(to)?"polboth":"pol")+"</ci>";
			  } else {
				  result+="<apply> <divide/> "+(graph.isInhibitor(to)?"<ci> displ </ci> <cn>"+Constants.polVm:"<cn>"+Constants.polVm)+"</cn>\n" 
					+ "<apply> <times/> <cn> "+(graph.isInhibitor(to)?Constants.polKmBoth:Constants.polKm)+"</cn>\n"
					+ "<apply> <plus/>\n"
					+ "<cn> 1 </cn>\n";
						
							result+="<apply> <divide/> <ci> tin"+from.ID+"to"+to.ID+" </ci> <cn> "+Constants.polKm+" </cn> </apply>\n";
							result+="<apply> <divide/> <ci> tboth"+graph.getEndpoints(temp).getFirst().ID+"to"+graph.getEndpoints(temp).getSecond().ID+" </ci> <cn> "+Constants.polKm+" </cn> </apply>\n";			
			result+="</apply>\n</apply>\n</apply>\n";
			  }
			  result+="</apply>\n"
			  +"</math>\n"
			  + "</kineticLaw>\n"
			  + "</reaction>\n";
			reactionnumber++;
			// nickase
			result+="<reaction id=\"R"+reactionnumber+"\" reversible=\"false\" fast=\"false\">\n"
			  +"<listOfReactants>\n"
			  +"<speciesReference species=\"text"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"</listOfReactants>\n"
			  +"<listOfProducts>\n"
			  +"<speciesReference species=\"tboth"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"</listOfProducts>\n"
			  +"<kineticLaw>\n"
			  +"<math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n"
			  +"<apply>\n"
			  +"<times/>"; 
			  if(graph.coupling||!graph.saturableNick){		
			  		result+=" <ci> nick </ci> ";
			  } else {
				  result+="<apply> <divide/> <cn> "+Constants.nickVm+"</cn>\n" 
					+ "<apply> <times/> <cn> "+Constants.nickKm+"</cn>\n"
						+ "<apply> <plus/>\n"
							+ "<cn> 1 </cn>\n";
							
								result+="<apply> <divide/> <ci> text"+graph.getEndpoints(temp).getFirst().ID+"to"+graph.getEndpoints(temp).getSecond().ID+" </ci> <cn> "+Constants.nickKm+" </cn> </apply>\n";
							
				result+="</apply>\n</apply>\n</apply>\n";
			  }
			  result+="<ci> text"+from.ID+"to"+to.ID+"</ci>\n"
			  +"</apply>\n"
			  +"</math>\n"
			  + "</kineticLaw>\n"
			  + "</reaction>\n";
			reactionnumber++;
			//inhibition
			if(inhib!=null){
				result+="<reaction id=\"R"+reactionnumber+"\" reversible=\"true\" fast=\"false\">\n"
				  +"<listOfReactants>\n"
				  +"<speciesReference species=\"s"+inhib.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
				  +"<speciesReference species=\"talone"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
				  +"</listOfReactants>\n"
				  +"<listOfProducts>\n"
				  +"<speciesReference species=\"tinhib"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
				  +"</listOfProducts>\n"
				  +"<kineticLaw>\n"
				  +"<math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n"
				  +"<apply>\n"
				  +"<times/> <ci> kduplex </ci> <ci> s"+inhib.ID+" </ci> <ci> talone"+from.ID+"to"+to.ID+"</ci>\n"
				  +"</apply>\n"
				  +"</math>\n"
				  + "</kineticLaw>\n"
				  + "</reaction>\n";
				reactionnumber++;
				result+="<reaction id=\"R"+reactionnumber+"\" reversible=\"true\" fast=\"false\">\n"
				  +"<listOfReactants>\n"
				  +"<speciesReference species=\"tinhib"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
				  +"</listOfReactants>\n"
				  +"<listOfProducts>\n"
				  +"<speciesReference species=\"s"+inhib.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
				  +"<speciesReference species=\"talone"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
				  +"</listOfProducts>\n"
				  +"<kineticLaw>\n"
				  +"<math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n"
				  +"<apply>\n"
				  +"<times/> <ci> kduplex </ci> <ci> ks"+inhib.ID+" </ci> <ci> alpha </ci> <ci> tinhib"+from.ID+"to"+to.ID+"</ci>\n"
				  +"</apply>\n"
				  +"</math>\n"
				  + "</kineticLaw>\n"
				  + "</reaction>\n";
				reactionnumber++;
				//inhib and tin
				result+="<reaction id=\"R"+reactionnumber+"\" reversible=\"false\" fast=\"false\">\n"
				  +"<listOfReactants>\n"
				  +"<speciesReference species=\"s"+inhib.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
				  +"<speciesReference species=\"tin"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
				  +"</listOfReactants>\n"
				  +"<listOfProducts>\n"
				  +"<speciesReference species=\"tinhib"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
				  +"<speciesReference species=\"s"+from.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
				  +"</listOfProducts>\n"
				  +"<kineticLaw>\n"
				  +"<math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n"
				  +"<apply>\n"
				  +"<times/> <ci> kduplex </ci> <ci> s"+inhib.ID+" </ci> <ci> tin"+from.ID+"to"+to.ID+"</ci>\n"
				  +"</apply>\n"
				  +"</math>\n"
				  + "</kineticLaw>\n"
				  + "</reaction>\n";
				reactionnumber++;
				//inhib and tout
				result+="<reaction id=\"R"+reactionnumber+"\" reversible=\"false\" fast=\"false\">\n"
				  +"<listOfReactants>\n"
				  +"<speciesReference species=\"s"+inhib.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
				  +"<speciesReference species=\"tout"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
				  +"</listOfReactants>\n"
				  +"<listOfProducts>\n"
				  +"<speciesReference species=\"s"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
				  +"<speciesReference species=\"tinhib"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
				  +"</listOfProducts>\n"
				  +"<kineticLaw>\n"
				  +"<math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n"
				  +"<apply>\n"
				  +"<times/> <ci> kduplex </ci> <ci> s"+inhib.ID+" </ci> <ci> tout"+from.ID+"to"+to.ID+"</ci>\n"
				  +"</apply>\n"
				  +"</math>\n"
				  + "</kineticLaw>\n"
				  + "</reaction>\n";
				reactionnumber++;
				if(Constants.ratioToehold>0){
					//tinhib and sin
					result+="<reaction id=\"R"+reactionnumber+"\" reversible=\"false\" fast=\"false\">\n"
					  +"<listOfReactants>\n"
					  +"<speciesReference species=\"s"+from.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
					  +"<speciesReference species=\"tinhib"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
					  +"</listOfReactants>\n"
					  +"<listOfProducts>\n"
					  +"<speciesReference species=\"tin"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
					  +"<speciesReference species=\"s"+inhib.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
					  +"</listOfProducts>\n"
					  +"<kineticLaw>\n"
					  +"<math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n"
					  +"<apply>\n"
					  +"<times/> <ci> kduplex </ci> <ci> tau </ci> <ci> s"+from.ID+" </ci> <ci> tinhib"+from.ID+"to"+to.ID+"</ci>\n"
					  +"</apply>\n"
					  +"</math>\n"
					  + "</kineticLaw>\n"
					  + "</reaction>\n";
					reactionnumber++;
					//tinhib and sout
					result+="<reaction id=\"R"+reactionnumber+"\" reversible=\"false\" fast=\"false\">\n"
					  +"<listOfReactants>\n"
					  +"<speciesReference species=\"s"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
					  +"<speciesReference species=\"tinhib"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
					  +"</listOfReactants>\n"
					  +"<listOfProducts>\n"
					  +"<speciesReference species=\"s"+inhib.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
					  +"<speciesReference species=\"tout"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
					  +"</listOfProducts>\n"
					  +"<kineticLaw>\n"
					  +"<math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n"
					  +"<apply>\n"
					  +"<times/> <ci> kduplex </ci> <ci> tau </ci> <ci> s"+to.ID+" </ci> <ci> tinhib"+from.ID+"to"+to.ID+"</ci>\n"
					  +"</apply>\n"
					  +"</math>\n"
					  + "</kineticLaw>\n"
					  + "</reaction>\n";
					reactionnumber++;
				}
			}
			if(graph.selfStart){
		    //leak talone -> tout
			result+="<reaction id=\"R"+reactionnumber+"\" reversible=\"false\" fast=\"false\">\n"
			  +"<listOfReactants>\n"
			  +"<speciesReference species=\"talone"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"</listOfReactants>\n"
			  +"<listOfProducts>\n"
			  +"<speciesReference species=\"tout"+from.ID+"to"+to.ID+"\" stoichiometry=\"1\" constant=\"true\"/>\n"
			  +"</listOfProducts>\n";
			  if(!graph.coupling&&graph.saturablePoly){
				  result+="<listOfModifiers>\n"
				  +"<modifierSpeciesReference species=\"tboth"+from.ID+"to"+to.ID+"\"/>"
				  +"</listOfModifiers>";

			  }
			  result+="<kineticLaw>\n"
			  +"<math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n"
			  +"<apply>\n"
			  +"<times/> <ci> polZerothOrderLeak </ci> <ci> talone"+from.ID+"to"+to.ID+"</ci>\n";
			  if(graph.coupling||!graph.saturablePoly){
			  result+= "<ci> pol </ci>"
			  ;
			  } else {
			  result+="<apply> <divide/> <cn> "+Constants.polVm+"</cn>\n" 
				+ "<apply> <times/> <cn> "+Constants.polKm+"</cn>\n"
				+ "<apply> <plus/>\n"
				+ "<cn> 1 </cn>\n";
					
						result+="<apply> <divide/> <ci> tin"+from.ID+"to"+to.ID+" </ci> <cn> "+Constants.polKm+" </cn> </apply>\n";
						result+="<apply> <divide/> <ci> tboth"+graph.getEndpoints(temp).getFirst().ID+"to"+graph.getEndpoints(temp).getSecond().ID+" </ci> <cn> "+Constants.polKm+" </cn> </apply>\n";			
						result+="</apply>\n</apply>\n</apply>\n";
			  }
			  result+="</apply>\n"
			  +"</math>\n"
			  + "</kineticLaw>\n"
			  + "</reaction>\n";
			reactionnumber++;
			}
		}
		return result;
	}
	
	public static <E> String exportToSBMLcode(OligoGraph<SequenceVertex,E> graph){
		InputStream in = CodeGenerator.class.getClassLoader().getResourceAsStream("utils/SBML");
		StringBuffer fileData = new StringBuffer();
		try {
			BufferedReader reader = new BufferedReader(
					new InputStreamReader(in));
			String line = null;
			while ((line = reader.readLine()) != null) {
				fileData.append(line+"\n");
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return fileData.toString().replace("<NAME>","ToolboxSystem").replace("<params>", SBMLparams(graph)).replace("<rules>",SBMLrules(graph)).replace("<species>",SBMLspecies(graph)).replace("<rules>",SBMLrules(graph)).replace("<reactions>", SBMLreactions(graph));
	}
}
